/**
 * @file Vector3.h
 * @author alejopelaez
 *
 * @section LICENSE
 *
 * Copyright 2011 Alejandro Peláez Roldán
 *
 * This file is part of Atom Physics Engine.
 * Atom Physics Engine is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Atom Physics Engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Atom Physics Engine.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef _VECTOR3_H_
#define _VECTOR3_H_

#include <atom/core/math/MyMath.h>

namespace atom{
    /**
	 * @class Vector3 Vector3.h Vector3.cpp
     * Class that represents a 3 dimensional vector.
     * This class abstracts all the operations and manipulations you
     * normally use on vectors.
     */
    class Vector3{
    public:
        real x;    /**< The x component of the vector */
        real y;    /**< The y component of the vector */
        real z;    /**< The z component of the vector */

        /**
         * Constructor.
         * Each of the coordinates are optional.
         * @param x The x component
         * @param y The y component
         * @param z The z component
         */
        Vector3(real x=0.0, real y=0.0, real z=0.0);

        /**
         * Destructor.
         */
        virtual ~Vector3();

        /**
         * @name Setters and getters
         */
		//@{

        /**
         * Quickly sets the compnents of the vector
         * @param x The x component
         * @param y The y component
         * @param z The z component
         */
        void setComponents(real x, real y, real z);
        /**
         * Quickly sets the compnents of the vector
         * @param components An array containing the new components
         */
        void setComponents(real components[]);
        /**
         * Overloading of [] to get the desired element
         * @param nIndex The index of the element to retrieve, x is 0, y is 1, z is 2.
         * @return The desired component.
         */
        real& operator[] (const int nIndex);
        /**
         * Gets the components of the vector as an array.
         * @return An array containing the components of the vector.
         */
        real* getComponents();
		//@}

        /**
         * @name Unary operations
         */
		//@{
        /**
         * Calculate the square of magnitude of the vector.
         * @return The square of the magnitude of the vector.
         */
        real magnitudeSqr(){return x*x + y*y + z*z;}
        /**
         * Calculate the magnitude of the vector.
         * @return The magnitude of the vector.
         */
        real magnitude(){return sqrt(magnitudeSqr());}
        /**
         * Normalize this vector.
         * This operation modifies the current vector.
         */
        void normalize(){
            real norm = magnitude();
            x /= norm; y /= norm; z /= norm;
        }
        /**
         * Normalize the vector.
         * This does not modify the vector, it just creates a new vector with the new components.
         * @param vector The vector onto which to write the new components.
         */
        void normalize(Vector3 &vector){
            real norm = magnitude();
            vector.setComponents(x/norm,y/norm,z/norm);
        }
        /**
         * Change the sign of the vector.
         * This operation modifies the vector.
         */
        void negative(){x=-x;y=-y;z=-z;}
        /**
         * Change the sign of the vector.
         * This method does not modify the vector, it writes the result on another vector instead.
         * @param vector The vector onto which to write the results.
         */
        void negative(Vector3 &vector){vector.x = -x; vector.y = -y; vector.z = -z;}
		//@}

        /**
         * @name Binary operations
         */
		//@{
        /**
         * Add two vectors together.
         * This overloads the + operator.
         */
        Vector3 operator+(const Vector3 &other){return Vector3(x+other.x,y+other.y,z+other.z);}
        /**
         * Substract one vector from another.
         * This overloads the - operator.
         */
        Vector3 operator-(const Vector3 &other){return Vector3(x-other.x,y-other.y,z-other.z);}
		//@}
    };
}

#endif /* _VECTOR3_H_ */
